#include <gtk/gtk.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#define SetString(a,b)  strcpy((a=malloc(strlen(b)+1)),b)

char* fname = NULL;
unsigned int Offset  = 0x00000000,            SearchSize = 0x00000000;
GtkWidget *openrom   = NULL, *search    = NULL;
GtkWidget *mbox      = NULL, *bbox      = NULL, *sizebox = NULL, *offsetbox = NULL;
GtkWidget *filename  = NULL, *sizetxt   = NULL, *offstxt = NULL;
GtkWidget *sizelbl   = NULL, *offslbl   = NULL;
GtkWidget *win       = NULL;
GtkResponseType ShowQuestion(char* text, char* title,gpointer window){
	GtkWidget *dialog;
	dialog = gtk_message_dialog_new(window,
		GTK_DIALOG_DESTROY_WITH_PARENT,
		GTK_MESSAGE_QUESTION,
		GTK_BUTTONS_YES_NO,
		text);
	gtk_window_set_title(GTK_WINDOW(dialog), title);
	GtkResponseType ret = gtk_dialog_run(GTK_DIALOG(dialog));
	gtk_widget_destroy(dialog);
	return ret;
}
unsigned int GetFileSize(FILE* file){
	unsigned int opos = ftell(file);
	fseek(file,0,SEEK_END);
	unsigned int ret = ftell(file);
	fseek(file,opos,SEEK_SET);
	return ret;
}
static void numberentry_textinsert(GtkEntryBuffer* buffer,int a,char* str,int b,unsigned int* val){
	char* text;SetString(text,gtk_entry_buffer_get_text(buffer));
	char* orig = text;
	int i;for(i=0;text[i]!='\0';i++) text[i]=toupper(text[i]);
	int hex=0;
	if((text[0]=='0'&&text[1]=='X')||(text[0]=='&'&&text[1]=='H')||text[0]=='$') hex = 1;
	if(hex==1){
		if((text[0]=='0'&&text[1]=='X')||(text[0]=='&'&&text[1]=='H')) text+=2;
		else text++;
	}
	sscanf(text,(hex==0)? "%i":"%X",val);
	*val &=0x1FFFFFF;
	free(orig);
}
static void search_push(){
	FILE *f=fopen(fname, "rb");
	if(!f) {fprintf(stderr,"Couldn't open file %s\n!",fname); return;}
	fseek(f, 0, SEEK_END);
	unsigned int size=ftell(f);
	fseek(f, 0, SEEK_SET);
	unsigned char *data=malloc(size);
	fread(data, size, 1, f);
	char* temp = NULL;
	unsigned char *cursor=data+Offset;
	unsigned char *end=data+size;
	while(1) {
		while(*cursor++!=0xFF) if(cursor>=end) return;
		unsigned char *freespace=cursor;
		while(*cursor++==0xFF) if(cursor>=end) return;
		if(cursor-freespace>=SearchSize){
			temp = (char*)malloc(1024);sprintf(temp,"0x%X",freespace-data);
			gtk_entry_set_text((GtkEntry*)offstxt,temp);
			free(temp);
		}
	}
	free(data);
	fclose(f);
}
static void openrom_push (){
	GtkWidget* FileDialog = gtk_file_chooser_dialog_new("Open Your ROM",(GtkWindow*)(win),GTK_FILE_CHOOSER_ACTION_OPEN,
								GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,NULL);
	if (gtk_dialog_run (GTK_DIALOG (FileDialog)) == GTK_RESPONSE_ACCEPT){
	if(fname)free(fname);
	gtk_widget_hide(FileDialog);
	fname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (FileDialog));
	gtk_label_set_text((GtkLabel*)filename,(const char*)fname);
	gtk_widget_show_all(win);
	}
	else {
		gtk_widget_hide(FileDialog);
		if(fname) if(ShowQuestion("Close the current file?","Input needed",win) == GTK_RESPONSE_YES)    {
			free(fname); 
			fname = NULL;
			gtk_button_set_label((GtkButton*)openrom,"Open A ROM");
			gtk_widget_show_all (win);
			gtk_widget_hide_all (offsetbox);
			gtk_widget_hide_all (sizebox);
			gtk_widget_hide     (search);
			gtk_widget_hide     (filename);
		}
	}
	gtk_widget_destroy(FileDialog);
}
static void quit(){
	if(fname){free(fname);}
	gtk_main_quit();
}
int main (int argc, char *argv[]){
	gtk_init (&argc, &argv);
	win       = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	openrom   = gtk_button_new_with_label("Open ROM");
	search    = gtk_button_new_with_label("Search!");
	mbox      = gtk_vbox_new(TRUE,5);
	bbox      = gtk_hbox_new(TRUE,5);
	sizebox   = gtk_hbox_new(TRUE,5);
	offsetbox = gtk_hbox_new(TRUE, 5);
	sizetxt   = gtk_entry_new();
	offstxt   = gtk_entry_new();
	filename  = gtk_label_new("FILENAME");
	sizelbl   = gtk_label_new(NULL);
	offslbl   = gtk_label_new(NULL);

	gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER);
	gtk_window_set_title   (GTK_WINDOW(win), "Full Metal Free Space");
	gtk_container_set_border_width(GTK_CONTAINER(win), 5);

	gtk_label_set_markup(GTK_LABEL(sizelbl), "<b>Size:</b>");
	gtk_label_set_markup(GTK_LABEL(offslbl), "<b>Offset:</b>");
	gtk_label_set_justify(GTK_LABEL(sizelbl), GTK_JUSTIFY_LEFT);
	gtk_label_set_justify(GTK_LABEL(offslbl), GTK_JUSTIFY_LEFT);
	gtk_label_set_justify(GTK_LABEL(filename),GTK_JUSTIFY_CENTER);

	gtk_box_pack_start(GTK_BOX(bbox), openrom, TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(bbox), search , TRUE, TRUE, 0);

	gtk_box_pack_start(GTK_BOX(sizebox), sizelbl, TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(sizebox), sizetxt, TRUE, TRUE, 0);

	gtk_box_pack_start(GTK_BOX(offsetbox), offslbl, TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(offsetbox), offstxt, TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(mbox), sizebox, TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(mbox), offsetbox, TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(mbox), filename, TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(mbox), bbox, TRUE, TRUE, 0);

	g_signal_connect (openrom,"clicked",openrom_push,NULL);
	g_signal_connect (search ,"clicked",search_push,NULL);
	g_signal_connect (gtk_entry_get_buffer((GtkEntry*)sizetxt),"inserted-text",G_CALLBACK(numberentry_textinsert),(gpointer)&SearchSize);
	g_signal_connect (gtk_entry_get_buffer((GtkEntry*)offstxt),"inserted-text",G_CALLBACK(numberentry_textinsert),(gpointer)&Offset);
	g_signal_connect (gtk_entry_get_buffer((GtkEntry*)sizetxt),"deleted-text" ,G_CALLBACK(numberentry_textinsert),(gpointer)&SearchSize);
	g_signal_connect (gtk_entry_get_buffer((GtkEntry*)offstxt),"deleted-text" ,G_CALLBACK(numberentry_textinsert),(gpointer)&Offset);
	g_signal_connect (win,"destroy",quit, NULL);

	/* Enter the main loop */
	gtk_container_add(GTK_CONTAINER(win), mbox);
	gtk_widget_show_all (win);
	gtk_widget_hide_all (offsetbox);
	gtk_widget_hide_all (sizebox);
	gtk_widget_hide     (search);
	gtk_widget_hide     (filename);
	gtk_main ();
  return 0;
}

